﻿#include "ssTimerThread.h"
#include "../ssTime.h"

namespace StarSeeker
{

ssTimerThread::ssTimerThread()
:m_msgHeap(true), m_pDispatch(0)
{
	m_condGet.BindLock(&m_mutex);
	m_ids.Init(1, 4000000000);
}

ssTimerThread::~ssTimerThread()
{
	ExitThread();
}

void ssTimerThread::BindDispatch(ssTimerDispatch* dis)
{
	m_pDispatch = dis;
}

u32 ssTimerThread::AddTimer(u32 msgType, u32 time, u32 interval, ulint p1, ulint p2)
{
	if (msgType != SS_TIMER_REPEAT && msgType != SS_TIMER_ONCE && msgType != SS_THREAD_STOP)
		return 0;

	ssTimer_s msg;
	msg.msgID = msgType;
	msg.time = time;
	msg.interval = interval;
	msg.param[0] = p1;
	msg.param[1] = p2;
	SS_MUTEX_LOCK(m_mutex)
		msg.subID = m_ids.GetID();
		m_msgHeap.Push(msg);
	SS_MUTEX_UNLOCK(m_mutex)
	m_condGet.NotifyAll();
	return msg.subID;
}

void ssTimerThread::StartHalfTimer()
{
	u32 now = ssTime::GetTimeNow().u32p;
	u32 beg = 1800 - now % 1800;
	AddTimer(SS_TIMER_HALF_HOUR, now + beg, 0, 0, 0);
}

u32 ssTimerThread::AddNewTimer(u32 msgType, u32 interval, ulint param1, ulint param2)
{
	return AddTimer(msgType, ssTime::GetTimeNow().u32p + interval, interval, param1, param2);
}

void ssTimerThread::RemoveTimer(u32 timerId)
{
	SS_MUTEX_LOCK(m_mutex);
	ssNumArray<ssTimer_s>& a = SS_CONST_CAST(ssNumArray<ssTimer_s>&, m_msgHeap.Array());
	for (ulint i = 0; i < a.Count(); ++i)
	{
		if (a[i].subID == timerId)
		{
			a[i].msgID = SS_TIMER_DEL;
			break;
		}
	}
	SS_MUTEX_UNLOCK(m_mutex);
}

void ssTimerThread::ThreadMemberFunc()
{
	while (!IsRequestStop())
	{
		ssTimer_s top;
		u32 now = 0;

		SS_MUTEX_LOCK(m_mutex); //锁定互斥量
		while (m_msgHeap.Count() == 0)
		{
			m_condGet.Wait(); //条件变量等待
		}

		now = ssTime::GetTimeNow().u32p;
		top = m_msgHeap.Top();
		if (now > top.time)
		{
			m_msgHeap.Pop();
		}
		else
		{
			top.msgID = SS_TIMER_DEL;
		}
		SS_MUTEX_UNLOCK(m_mutex);

		switch (top.msgID)
		{
		case SS_TIMER_ONCE://单次计时器
			{
				if (m_pDispatch)
					m_pDispatch->Dispatch(top.msgID, top.subID, top.param[0], top.param[1]);
			}
			break;
		case SS_TIMER_REPEAT://重复计时器
			{
				if (m_pDispatch)
					m_pDispatch->Dispatch(top.msgID, top.subID, top.param[0], top.param[1]);
				top.time = now + top.interval;
				SS_MUTEX_LOCK(m_mutex);
				m_msgHeap.Push(top);
				SS_MUTEX_UNLOCK(m_mutex);
			}
			break;
		case SS_TIMER_HALF_HOUR://半点计时器
			{
				if (m_pDispatch)
					m_pDispatch->Dispatch(top.msgID, top.subID, top.param[0], top.param[1]);
				u32 beg = 1800 - now % 1800;
				top.time = now + beg;
				SS_MUTEX_LOCK(m_mutex);
				m_msgHeap.Push(top);
				SS_MUTEX_UNLOCK(m_mutex);
			}
			break;
		case SS_THREAD_STOP:
			RequestStop();
			break;
		default:
			break;
		}
	}
}

void ssTimerThread::ExitThread()
{
	AddTimer(SS_THREAD_STOP, 0, 0, 0, 0);
	ssThreadBase::Sleep(500);
	WaitForExit();
}

StarSeeker::ulint ssTimerThread::GetTimerCount()
{
	return m_msgHeap.Count();
}

}
